package com.uchonor.api.core.service;

import com.uchonor.api.core.converts.*;
import com.uchonor.api.core.dto.ColumnsInfo;
import com.uchonor.api.core.dto.TableInfo;
import com.uchonor.api.core.query.*;
import com.uchonor.api.utils.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public abstract class AbsDataSourceMetaDataStrategy implements IDataSourceMetaDataStrategy {

    private String driverName;

    protected ITypeConvert typeConvert;

    public boolean supper(String driverName){
        this.driverName = driverName;
        return getDbType().equals(getSupperDbType());
    }

    public IDbQuery getDbQuery() {
        DbType dbType = getDbType();
        IDbQuery dbQuery = null;
        switch (dbType) {
            case ORACLE:
                dbQuery = new OracleQuery();
                break;
            case SQL_SERVER:
                dbQuery = new SqlServerQuery();
                break;
            case POSTGRE_SQL:
                dbQuery = new PostgreSqlQuery();
                break;
            case DB2:
                dbQuery = new DB2Query();
                break;
            case MARIADB:
                dbQuery = new MariadbQuery();
                break;
            default:
                // 默认 MYSQL
                dbQuery = new MySqlQuery();
                break;
        }
        return dbQuery;
    }

    public DbType getDbType() {
        DbType dbType = null;
        String driverName = this.driverName.toLowerCase();
        if (driverName.contains("mysql")) {
            dbType = DbType.MYSQL;
        } else if (driverName.contains("oracle")) {
            dbType = DbType.ORACLE;
        } else if (driverName.contains("postgresql")) {
            dbType = DbType.POSTGRE_SQL;
        } else if (driverName.contains("db2")) {
            dbType = DbType.DB2;
        } else if (driverName.contains("mariadb")) {
            dbType = DbType.MARIADB;
        } else {
            throw new RuntimeException("Unknown type of database!");
        }
        return dbType;
    }

    protected ITypeConvert getTypeConvert() {
        DbType dbType = getDbType();
        if (null == typeConvert) {
            switch (dbType) {
                case ORACLE:
                    typeConvert = new OracleTypeConvert();
                    break;
                case SQL_SERVER:
                    typeConvert = new SqlServerTypeConvert();
                    break;
                case POSTGRE_SQL:
                    typeConvert = new PostgreSqlTypeConvert();
                    break;
                case DB2:
                    typeConvert = new DB2TypeConvert();
                    break;
                case MARIADB:
                    typeConvert = new MySqlTypeConvert();
                    break;
                default:
                    // 默认 MYSQL
                    typeConvert = new MySqlTypeConvert();
                    break;
            }
        }
        return typeConvert;
    }

    protected abstract DbType getSupperDbType();

    protected abstract String buildTableSql(String tableSchema);

    protected abstract String getFiledSql(String tableName,String tableSchema);

    /**
     * <p>
     * 处理表/字段名称
     * </p>
     *
     * @param name
     * @param strategy
     * @param prefix
     * @return 根据策略返回处理后的名称
     */
    protected String processName(String name, NamingStrategy strategy, String[] prefix) {
        boolean removePrefix = false;
        if (prefix != null && prefix.length >= 1) {
            removePrefix = true;
        }
        String propertyName;
        if (removePrefix) {
            if (strategy == NamingStrategy.underline_to_camel) {
                // 删除前缀、下划线转驼峰
                propertyName = NamingStrategy.removePrefixAndCamel(name, prefix);
            } else {
                // 删除前缀
                propertyName = NamingStrategy.removePrefix(name, prefix);
            }
        } else if (strategy == NamingStrategy.underline_to_camel) {
            // 下划线转驼峰
            propertyName = NamingStrategy.underlineToCamel(name);
        } else {
            // 不处理
            propertyName = name;
        }
        return propertyName;
    }

    @Override
    public List<TableInfo> getAllTableList(JdbcTemplate jdbcTemplate, String tableSchema) {
        IDbQuery iDbQuery = getDbQuery();
        List<TableInfo> tableInfoList = new ArrayList<>();
        List<Map<String, Object>> mapList = jdbcTemplate.queryForList(buildTableSql(tableSchema));
        if (mapList != null && mapList.size() > 0) {
            for (Map<String, Object> map : mapList) {
                TableInfo tableInfo = new TableInfo();
                String tableName = ObjectUtils.nullSafeToString(map.get(iDbQuery.tableName()));
                if (!StringUtils.isEmpty(tableName)) {
                    String tableComment = ObjectUtils.nullSafeToString(map.get(iDbQuery.tableComment()));
                    tableInfo.setTableName(tableName);
                    tableInfo.setTableComment(tableComment);
                    tableInfoList.add(tableInfo);
                }
            }
        }
        return tableInfoList;
    }

    @Override
    public List<ColumnsInfo> getColumnsInfo(JdbcTemplate jdbcTemplate, String tableSchema, String tableName) {
        List<ColumnsInfo> columnsInfoList = new ArrayList<>();
        IDbQuery iDbQuery = getDbQuery();
        String tableSql = getFiledSql(tableName,tableSchema);
        ColumnsInfo columnsInfo = null;
        List<Map<String,Object>> tableFiledList = jdbcTemplate.queryForList(tableSql);
        if(tableFiledList!=null && tableFiledList.size()>0) {
            for (Map<String, Object> data : tableFiledList) {
                columnsInfo = new ColumnsInfo();
                String key = ObjectUtils.nullSafeToString(data.get(iDbQuery.fieldKey()));
                boolean isId = StringUtils.isNotEmpty(key) && iDbQuery.pkFiled().equals(key.toUpperCase());
                if(isId && iDbQuery.isKeyIdentity(data)){
                    columnsInfo.setKeyIdentityFlag(true);
                }
                columnsInfo.setIsPk(isId);
                String columnsName = ObjectUtils.nullSafeToString(data.get(iDbQuery.fieldName()));
                columnsInfo.setColumnsName(columnsName.toLowerCase());
                String fieldType = ObjectUtils.nullSafeToString(data.get(iDbQuery.fieldType()));
                columnsInfo.setDataType(fieldType);
                columnsInfo.setColumnsComment(ObjectUtils.nullSafeToString(data.get(iDbQuery.fieldComment())));
                IColumnType iColumnType = getTypeConvert().processTypeConvert(DateType.ONLY_DATE, fieldType);
                columnsInfo.setJavaType(iColumnType.getType());
                columnsInfo.setJavaPkg(iColumnType.getPkg());
                columnsInfo.setPropertiesName(processName(columnsName, NamingStrategy.underline_to_camel,null));
                columnsInfoList.add(columnsInfo);
            }
        }
        return columnsInfoList;
    }
}
